#include "ola_stdio.h"
#include "ola_string.h"
#include "ola_memory.h"
#include "ola_softap.h"

#ifdef __ESP_32_PAL__
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"
#endif


#ifdef __ESP_32_PAL__
/* The examples use WiFi configuration that you can set via 'make menuconfig'.

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID      ("OLA1JD")
#define EXAMPLE_ESP_WIFI_PASS      ("olaolaola")
#define EXAMPLE_MAX_STA_CONN       (3)

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
static const char *TAG = "OLA wifi softAP";
const int WIFI_CONNECTED_BIT = BIT0;
int g_net_status = 0;

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    switch(event->event_id) {
    case SYSTEM_EVENT_AP_STACONNECTED:
        ESP_LOGI(TAG, "station:"MACSTR" join, AID=%d",
                 MAC2STR(event->event_info.sta_connected.mac),
                 event->event_info.sta_connected.aid);
        break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
        ESP_LOGI(TAG, "station:"MACSTR"leave, AID=%d",
                 MAC2STR(event->event_info.sta_disconnected.mac),
                 event->event_info.sta_disconnected.aid);
        break;
    case SYSTEM_EVENT_STA_START:
        esp_wifi_connect();
        break;
    case SYSTEM_EVENT_STA_GOT_IP:
        ESP_LOGI(TAG, "got ip:%s",
                 ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
        break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
        {
            g_net_status = 0;
            xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
            ESP_LOGI(TAG,"Disconnect from the AP\n");
            break;
        }
    case SYSTEM_EVENT_STA_CONNECTED:
    {
        g_net_status = 1;
        ESP_LOGI(TAG,"Connect to the AP success\n");
        break;
    }
    default:
        break;
    }
    return ESP_OK;
}

int ola_softap_start(unsigned int timeout_ms){
    return 1;
}

void wifi_init_softap()
{
    s_wifi_event_group = xEventGroupCreate();

    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config;
    ola_pal_memset(&wifi_config, 0, sizeof(wifi_config_t));
    wifi_config.ap.ssid_len = ola_pal_strlen(EXAMPLE_ESP_WIFI_SSID);
    if (wifi_config.ap.ssid_len > sizeof(wifi_config.ap.ssid)) {
        wifi_config.ap.ssid_len = sizeof(wifi_config.ap.ssid);
    }
    ola_pal_strcpy((char *)wifi_config.ap.ssid, EXAMPLE_ESP_WIFI_SSID);
    wifi_config.ap.max_connection = 3;
    wifi_config.ap.channel = 9;

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}



#endif

/**
 * @brief:set wifi mode to AP mode.
 *
 * @returns:success 0, others failed
 */
int32_t ola_pal_softap_enter_ap_mode(void)
{
    // open wifi whit AP mode
#ifdef __LINUX_PAL__
    return 0;
#elif defined (__ESP_32_PAL__)
    ola_pal_printf("Enter ola_pal_softap_enter_ap_mode... \r\n");
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    
    ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
    wifi_init_softap();
    ola_pal_printf("Leave ola_pal_softap_enter_ap_mode... \r\n");
    return 0;
#else
    return 0;
#endif
}


/**
 * @brief:System is expected to get product information that user regiested in Cloud platform.
 *
 * @param[out]: UUID , max length: 8
 * @param[out]: BRAND, max length: 8 
 * @param[out]: CID,   max length: 8
 * @param[out]: dev_soft_ssid max length: 32
 *
 * @returns:success 0, others failed
 */
int32_t ola_pal_softap_get_product_info(char *uuid, char *brand, char *cid, char *dev_soft_ssid)
{
#ifdef __LINUX_PAL__
    char *_uuid = "CDEFC2";
    ola_pal_strcpy(uuid, _uuid);
    
    char* _dev_soft_ssid="martin";
    ola_pal_strcpy(dev_soft_ssid, _dev_soft_ssid);
    
    char *_cid = "25";
    ola_pal_strcpy(cid, _cid);

    char *_brand="45";
    ola_pal_strcpy(brand, _brand);
#elif defined (__ESP_32_PAL__)
    ola_pal_strcpy(uuid, "3B9728");
    
    ola_pal_strcpy(dev_soft_ssid, EXAMPLE_ESP_WIFI_SSID);
    
    char *_cid = "24";
    ola_pal_strcpy(cid, _cid);

    char *_brand="2";
    ola_pal_strcpy(brand, _brand);
#else
#endif    
    return 0;
}

#ifdef __ESP_32_PAL__

void wifi_init_sta(char *ssid, char *passwd)
{
    wifi_config_t wifi_config;
    ola_pal_memset(&wifi_config, 0, sizeof(wifi_config_t));
    ola_pal_strcpy((char *)wifi_config.sta.ssid, ssid);
    ola_pal_strcpy((char *)wifi_config.sta.password, passwd);

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");
    ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
             ssid, passwd);
}
#endif

/**
 * @brief:System is expected to connect wifi router with the in parameters.
 *
 * @param[in]: ssid of wifi router
 * @param[in]: passwd  of wifi router
 *
 * @returns:success 0, others failed
 */
int32_t ola_pal_softap_connect_wifi_router(char *ssid, char *passwd)
{
    // step 1 close AP mode

    // step 2 connect to the router
#ifdef __LINUX_PAL__
#elif defined (__ESP_32_PAL__)
	nvs_handle fd;
	ola_pal_printf("ola_dev_set_attr_jlp start\n");
	if (nvs_open("OLA", NVS_READWRITE, &fd) != ESP_OK) 
	{
		ola_pal_printf("nvs_open failed\n");
	}
	if (nvs_set_str(fd, "ssid", ssid) != ESP_OK) { 
		ola_pal_printf("--set ssid fail\n"); 
	} else {
		ola_pal_printf("--set ssid succeed: %s\n", ssid); 
	}
	if (nvs_set_str(fd, "pwd", passwd) != ESP_OK) { 
		ola_pal_printf("--set pwd fail\n"); 
	} else {
		ola_pal_printf("--set pwd succeed: %s\n", passwd); 
	}
    nvs_close(fd);

    ola_pal_printf("Enter ola_pal_softap_connect_wifi_router\r\n");
    ola_pal_printf("ssid: %s\tpasswd:%s\r\n",ssid ,passwd);
    
    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta(ssid, passwd);

    ola_pal_printf("Leave ola_pal_softap_connect_wifi_router\r\n");
#else
#endif
    return 0;
}
